#include <alloca.h>
#include <ghttp.h>
#include <string.h>

#include <xmlsec/xmltree.h>

#include "mcx.h"

const char *base = "http://mikolaj.cx/settlement/services/";
const char *ns_soap = "http://schemas.xmlsoap.org/soap/envelope/";
const char *ns_dws = "urn:doshwsdl";

static int dump = 0;

void mcx_debug_set(int d) { dump = d; }
int mcx_debug_get() { return dump; }

xmlDocPtr mcx_send(char *svc, xmlDocPtr doc) {
  xmlDocPtr envelope, response, ret;
  xmlNodePtr root, body;
  xmlNsPtr soapns;

  envelope = mcx_doc_new(ns_soap, "soap", "Envelope", &soapns, &root);
  body = xmlNewDocNode(envelope, soapns, "Body", NULL);
  xmlAddChild(root, body);
  xmlAddChild(body, xmlDocCopyNode(xmlDocGetRootElement(doc), envelope, 1));

  if(mcx_debug_get() > 1)
    xmlDocDump(stderr, envelope);
  response = mcx_send_raw(svc, envelope);
  if(mcx_debug_get() > 1)
    xmlDocDump(stderr, response);

  root = xmlDocGetRootElement(response);
  if(!root || !xmlSecCheckNodeName(root, "Envelope", ns_soap))
    return NULL;
  body = xmlSecFindChild(root, "Body", ns_soap);
  if(!body)
    return NULL;

  if(!body->children)
    return NULL;
  ret = xmlNewDoc("1.0");
  xmlDocSetRootElement(ret, xmlDocCopyNode(body->children, ret, 1));
  return ret;
}

xmlDocPtr mcx_send_raw(char *svc, xmlDocPtr doc) {
  unsigned char *buf, *url;
  unsigned int len, offset = 0;
  ghttp_request *request;
  ghttp_status stat;
  xmlDocPtr response;

  url = alloca(strlen(base) + strlen(svc) + 1);
  strcpy(url, base);
  strcat(url, svc);
  
  xmlDocDumpFormatMemory(doc, &buf, &len, 0);
  if(len >= 2 && buf[0] == '<' && buf[1] == '?') {
    unsigned char *start = memchr(buf + 1, '<', len - 1);
    if(start)
      offset = start - buf;
  }

  request = ghttp_request_new();
  if(!request)
    return NULL;
  ghttp_set_uri(request, url);
  ghttp_set_type(request, ghttp_type_post);
  ghttp_set_header(request, http_hdr_Connection, "close");
  ghttp_set_header(request, http_hdr_Content_Type, "text/xml");
  ghttp_set_header(request, "SOAPAction", "");
  ghttp_set_body(request, buf + offset, len - offset);
  ghttp_prepare(request);
  stat = ghttp_process(request);
  if(stat != ghttp_done)
    return NULL;
  response = xmlParseMemory(ghttp_get_body(request), ghttp_get_body_len(request));
  return response;
}
